package org.openea.eap.module.obpm.service.eap;

import cn.hutool.json.JSONObject;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;
import org.openea.eap.framework.common.enums.CommonStatusEnum;
import org.openea.eap.framework.common.util.collection.CollectionUtils;
import org.openea.eap.module.obpm.service.obpm.ObmpClientService;
import org.openea.eap.module.system.dal.dataobject.permission.MenuDO;
import org.openea.eap.module.system.dal.dataobject.user.AdminUserDO;
import org.openea.eap.module.system.service.permission.PermissionService;
import org.openea.eap.module.system.service.permission.PermissionServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.context.annotation.Primary;

import javax.annotation.Resource;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.util.*;


@Service
@Primary
@Slf4j
public class ObpmPermissionServiceImpl extends PermissionServiceImpl implements PermissionService {

    @Resource
    private ObmpClientService obmpClientService;


    /**
     * 集成obpm后原来topMenu排序迁移量
     */
    public static int menu_top_pos = 2000;
    /**
     * 集成obpm后原来MenuId迁移量
     */
    public static int menu_id_pos = 5000000;

    @Override
    public List<MenuDO> getUserMenuListByUser(Long userId, String userKey){
        // 1. eap menu
        List<MenuDO> menuList = super.getUserMenuListByUser(userId, userKey);

        // 2. obpm menu
        if(ObjectUtils.isEmpty(userKey)){
            AdminUserDO adminUserDO = userService.getUser(userId);
            if(adminUserDO!=null){
                userKey = adminUserDO.getUsername();
            }
        }
        // 用户菜单
        List<MenuDO> menuList2 = getObpmUserMenuList(userKey, true);
        // 管理菜单
        boolean withObpmAdmin = false;
        // 可扩展为查询某几类角色
        //if("admin".equals(userKey) || "eapadmin".equals(userKey)){
        if("eapadmin".equals(userKey)){
            withObpmAdmin = true;
        }
        List<MenuDO> menuList2Admin = null;
        if(withObpmAdmin){
            menuList2Admin = getObpmUserMenuList(userKey, "bpm", true);
        }

        // 3. 合并
        // 针对admin特别处理，避免admin拥有eap管理菜单
        if(!menuList2.isEmpty() && "admin".equals(userKey)){
            menuList = menuList2;
        }
        if(!menuList2.isEmpty() && !"admin".equals(userKey)){
            // obpm 菜单所有id/parentId + 2000000（避免同eap菜单冲突）
            for(MenuDO menu: menuList2){
                menu.setId(menu.getId()+menu_id_pos);
                if(menu.getParentId()!=0L){
                    menu.setParentId(menu.getParentId()+menu_id_pos);
                }
            }
            // obpm 后台开发管理菜单
            if(menuList2Admin!=null){
                for(MenuDO menu: menuList2Admin){
                    menu.setId(menu.getId()+menu_id_pos);
                    if(menu.getParentId()!=0L){
                        menu.setParentId(menu.getParentId()+menu_id_pos);
                    }
                    if(menu.getParentId()==0L){
                        menu.setSort(menu_top_pos/2+menu.getSort());
                    }
                    menuList2.add(menu);
                }
            }
            // eap 顶层菜单排序sort + 1000
            if(menuList!=null){
                for(MenuDO menu: menuList){
                    if(menu.getParentId()==0L){
                        menu.setSort(menu_top_pos+menu.getSort());
                    }
                    menuList2.add(menu);
                }
            }
            menuList = menuList2;
        }


        return menuList;
    }

    private List<MenuDO> getObpmUserMenuList(String userKey, boolean withButton) {
        return getObpmUserMenuList(userKey, null, withButton);
    }

    private List<MenuDO> getObpmUserMenuList(String userKey, String systemKey, boolean withButton) {
        List<MenuDO> listMenu = new ArrayList<>();
        // 保留用户前缀
        if(StringUtils.isEmpty(userKey) || userKey.startsWith("eap")){
            return listMenu;
        }
        List<JSONObject> listResource = obmpClientService.queryUserMenu(userKey, systemKey, withButton);
        if(listResource!=null){
            for(JSONObject sysRes: listResource){
                // 过滤不符合数据
                String systemId = sysRes.getStr("systemId");
                if("bpm".equals(systemKey) && !"1".equals(systemId)){
                    continue;
                }
                // ignore button
                String type = sysRes.getStr("type");
                if(!withButton){
                    if("button".equals(type)) {continue;}
                }
                if ("button".equals(type) && sysRes.getInt("enable", 0) != 1) {
                    continue;
                }
                listMenu.add(convertMenu(sysRes));
            }
        }
        return listMenu;
    }

    private MenuDO convertMenu(JSONObject sysRes){
        MenuDO menu = new MenuDO();
        // 1. copy
        // 1.1 same name
        // id, parentId, name, alias, icon, type
        //BeanUtils.copyProperties(sysRes, menu);
        menu.setId(sysRes.getLong("id", 0L));
        menu.setParentId(sysRes.getLong("parentId", 0L));
        if(menu.getParentId()==null){
            menu.setParentId(0L);
        }
        menu.setName(sysRes.getStr("name"));
        String alias = sysRes.getStr("alias");
        // 过滤可能url或vue route异常字符
        alias = alias.replaceAll("\\(","_").replaceAll("\\)","_");
        menu.setAlias(alias);

        //menuDO.setPermission( bean.getPermission() );
        // status/visible/keepAlive/alwaysShow
        menu.setStatus(CommonStatusEnum.ENABLE.getStatus());
        if(sysRes.getInt("enable",0)==0){
            menu.setVisible(false);
        }else{
            menu.setVisible(true);
        }
        menu.setKeepAlive(true);
        menu.setAlwaysShow(true);
        // 重用alwaysShow，1=默认打开 0=默认折叠
        // opened 默认是否打开
        if(sysRes.getInt("opened",0)==0){
            menu.setAlwaysShow(false);
        }

        // check type
        String type = sysRes.getStr("type");
        if("menu".equals(type)){
            menu.setType(2);
        }else if("button".equals(type)){
            menu.setType(3);
            menu.setVisible(false);
        }else{
            menu.setType(0);
        }

        // check sort (sn -> sort)
        int sort = 0;
        if(sysRes.containsKey("sn")){
            sort = sysRes.getInt("sn");
        }
        menu.setSort(sort);
        // icon
        String icon = sysRes.getStr("icon");
        if(ObjectUtils.isEmpty(icon)){
            if(menu.getParentId()==0L){
                // top default icon
                icon = "system";
            }
        }else{
//            icon = convertIcon(icon);
        }
        if(ObjectUtils.isNotEmpty(icon)){
            menu.setIcon(icon);
        }


        // 1.3 default prop

        // 2. 菜单转换 path
        // 2.1 通用 path (url -> path)
        String path = sysRes.getStr("url");
        String component = null;
        if(ObjectUtils.isEmpty(path)){
            path = menu.getAlias();
            // 子元素只有1个时可省略中间层级
//            menu.setAlwaysShow(false);
        }else{
            component = "obpm/web";
        }
        if(menu.getParentId()==0L){
            if(!path.startsWith("http") && !path.startsWith("/")){
                path = "/" + path;
            }
        }
        menu.setPath(path);
        if(ObjectUtils.isNotEmpty(component)){
            menu.setComponent(component);
        }
        // 2.2 检查 属性systemId和url参数subapp
        String systemId = sysRes.getStr("systemId");
//        if("1".equals(systemId)){
//            menu.setComponent("obpm/web2");
//        }
        String subapp = getParamValueFromPath(path, "subapp");
        if("web2".equals(subapp)){
            // wujie
            menu.setComponent("obpm/web2");
        }
        if("web1".equals(subapp)){
            // iframe
            menu.setComponent("obpm/web");
            return menu;
        }
        // wujie
        if("obpm/web2".equals(menu.getComponent())){
            return menu;
        }

        // 2.3 obpm web
        obpmWebMenu(menu, path);

        return menu;
    }


    private MenuDO obpmWebMenu(MenuDO menu, String path){
        // 2.1 obpm web, default setting
        //String componentName = null;
        String component = null;
        if(ObjectUtils.isEmpty(path)) {
            path = menu.getAlias();
            // 子元素只有1个时可省略中间层级
//            menu.setAlwaysShow(false);
        // 路径以 /views/ 开头，则解析为vue组件
        }else if (path.startsWith("/views/")){
            int n1 = path.indexOf("?");
            if(n1>0){
                component = path.substring(7, n1);
            }else{
                component = path.substring(7);
            }
        }else{
            component = "obpm/web";

            if(path.indexOf("originEtech=4567")>=0){

            }else{
                // 2.1  custSql or grid or treeGrid
                // /form/formCustSql/view/formCustSqlView.html?code=xxx
                // /form/formCustSql/view/formCustSqlViewByTree.html?code=xxx
                if(path.indexOf("form/formCustSql/view/formCustSqlView.html")>=0){
                    component = "obpm/agGrid";
                    String code = getParamValueFromPath(path, "code");
                    path = "obpm/listGrid/"+code
                            +path.substring(path.indexOf("formCustSqlView.html?")+20);
                }
                // 2.2 form
                // /form/formDef/vueFormDetail.html?key=xx
                // /form/formDef/vueFormDefPreview.html?key=xxx&&id=xxx
                if(path.indexOf("form/formDef/vueFormDefPreview.html")>=0){
                    component = "obpm/easyForm";
                    String key = getParamValueFromPath(path, "key");
                    path = "obpm/easyForm/"+key
                            +path.substring(path.indexOf("vueFormDefPreview.html?")+22);
                }

                // 2.3 dialog or support

                // 2.4 task
                // /bpm/vueForm/instanceDetail.html?id=xxx
                if(path.indexOf("bpm/vueForm/instanceDetail.html")>=0){
                    component = "obpm/instanceDetail";
                    String id = getParamValueFromPath(path, "id");
                    path = "obpm/instanceDetail/"+id
                            +path.substring(path.indexOf("instanceDetail.html?")+19);
                }
                // /bpm/vueForm/taskComplete.html?taskId=xxx
                if(path.indexOf("bpm/vueForm/taskComplete.html")>=0){
                    component = "obpm/taskDetail";
                    String taskId = getParamValueFromPath(path, "taskId");
                    path = "obpm/taskComplete/"+taskId
                            + path.substring(path.indexOf("taskComplete.html?")+17);
                }
                // /bpm/vueForm/start.html?defId=xxx
                // /bpm/vueForm/start.html?instanceId=xxx
                if(path.indexOf("bpm/vueForm/start.html")>=0){
                    component = "obpm/taskStart";
                    Map<String, String> mParam = getPathParams(path);
                    String id = mParam.get("defId");
                    if(ObjectUtils.isEmpty(id)){
                        id = mParam.get("instanceId");
                    }
                    path = "obpm/taskStart/"+id
                            +path.substring(path.indexOf("start.html?")+10);
                }

                // 2.5 etech 定制  etech/

                // 2.6 others
                // 2.6.1 _blank or http/https
                // http://[host]/[path]
                // _blank:http://[host]/[path]  _blank新tab或新窗口？
                // _blank:/etech/user/BuildingMap.html?isEdit=0&v=1.0

                // 2.6.2 javascript
                // javascript:scope.exportData(scope);

                // 2.6.3
                // path中参数${}由前端处理
                // /brand/submitTasks/${ids}


                // 2.8
                // admin(todo)
                // sys,org
                // bpm, form
            }



        }
        //2.9
        if(menu.getParentId()==0L){
            if(!path.startsWith("http") && !path.startsWith("/")){
                path = "/" + path;
            }
        }

        // set component and path
        if(ObjectUtils.isNotEmpty(path)){
            menu.setPath(path);
        }
        if(ObjectUtils.isNotEmpty(component)){
            menu.setComponent(component);
        }
        return menu;
    }
    private String convertIcon(String origin){
        // todo
        return "row";
    }

    private String[] getQueryParam4route(String path, String key){
        String keyValue = "nul";
        String queryPath = "";
        List<NameValuePair> listParam = URLEncodedUtils.parse(path.substring(path.indexOf("?")+1), Charset.forName("UTF-8"));
        for(NameValuePair pair: listParam){
            if(pair.getName().equals(key)){
                keyValue = pair.getValue();
            }else{
                queryPath += "/"+pair.getName()+"/"+pair.getValue();
            }
        }
        return new String[]{keyValue, queryPath};
    }

    private String getParamValueFromPath(String path, String key){
        Map<String, String> mParam = getPathParams(path);
        return  mParam.get(key);
    }
    private Map<String, String> getPathParams(String path) {
        Map<String, String> mParam = new HashMap<>();
        List<NameValuePair> listParam = URLEncodedUtils.parse(path.substring(path.indexOf("?")+1), Charset.forName("UTF-8"));
        for(NameValuePair pair: listParam){
            mParam.put(pair.getName(), pair.getValue());
        }
        return mParam;
    }
}
